define([
    'zTree.exhide'
], function(require, factory) {
    'use strict';

    /**
     * 自定义的selectTree
     * @param {object}  options 
     * @param {string}  id - 容器的id，必填
     * @param {object}  treeConfig - 树形的配置，参照ztree的配置
     * @param {array}   treeData - 显示树形的数据，数组
     * @param {string}  label - 显示的标题
     * @param {string}  mode - 模式，inline、block
     * @param {boolean} showSearch - 是否显示搜索框，默认为true
     * @param {object}  searchConfig { enable: true, level: 2, filter: function(){} }
     * @param {string}  nameField - 组件的name的字段key，默认为name
     * @param {string}  valueField - 组件的value的字段key，默认为value
     * @param {array}   value - 组件的默认值，为数组
     * @param {number}  showLevel - 显示树形的层级，从1开始
     */
    function SelectTree(options){
        if(!options.id){
            throw new Error('the id of container is missing !')
        }
        this.id = options.id;
        this.treeConfig = options.treeConfig;
        this.treeData = !options.treeData ? [] : JSON.parse(JSON.stringify(options.treeData));
        this.label = options.label;
        this.nameField = !options.nameField ? 'name' : options.nameField;
        this.valueField = !options.valueField ? 'value' : options.valueField;
        this.value = !options.value || !(options.value instanceof Array) ? [] : options.value;
        this.mode = !options.mode ? 'inline' : 'block';
        this.box = $('#'+this.id);
        this.showSearch = typeof options.showSearch === 'undefined' ? true : options.showSearch;
        this.searchConfig = !options.searchConfig ? { } : options.searchConfig;
        this.showLevel = !options.showLevel || typeof options.showLevel !== 'number' ? 0 : options.showLevel;
        this.init();
    }

    SelectTree.prototype.reloadTree = function(treeConfig, treeData){
        this.treeConfig = !treeConfig ? this.treeConfig : treeConfig;
        this.treeData = !treeData ? this.treeData : JSON.parse(JSON.stringify(options.treeData));
        this.showTree();
        this.initData();
    }

    /**
     * 组件初始化
     */
    SelectTree.prototype.init = function(){
        this.renderHtml();
        this.showTree();
        this.initData();
        this.setListener();
    }

    SelectTree.prototype.initData = function(){
        this.setValue(this.value);
    }

    /**
     * 组件进行设置值的方法
     * @param list - 设置值的value
     * list中的每一项的key需要与设定的nameField,valueField的字段名保持一致
     */
    SelectTree.prototype.setValue = function(list){
        list = list || [];
        var that = this;
        this.treeObj.checkAllNodes(false);
        list.forEach(function(item){
            var aNode = that.treeObj.getNodeByParam(that.valueField, item[that.valueField]);
            if(!!aNode){
                that.treeObj.checkNode(aNode, true);
            }
        });
        this.setInputValue(list);
    }

    /**
     * @param list - 设置显示的input的值
     */
    SelectTree.prototype.setInputValue = function(list){
        var name = '', value = '';
        var that = this;
        list.forEach(function(item){
            name += (!name ? '' : ',') + item[that.nameField];
            value += (!value ? '' : ',') + item[that.valueField];
        })
        this.box.find('.tree-input').val(name).data('value', value);
    }

    /**
     * 组件获取选择值的方法
     * @returns {object} - 返回选择的值的字符串
     */
    SelectTree.prototype.getValue = function(){
        var that = this;
        var check_nodes = this.treeObj.getCheckedNodes();
        var name = '', value = '';
        check_nodes.forEach(function(item){
            name += (!name ? '' : ',') + item[that.nameField];
            value += (!value ? '' : ',') + item[that.valueField];
        })
        return {
            name: name,
            value: value
        }
    }

    /**
     * 根据当前input中存储的值进行tree的回显
     */
    SelectTree.prototype.resetTreeByInputValue = function(){
        var that = this;
        var names = this.box.find('.tree-input').val().split(',');
        var values = this.box.find('.tree-input').data('value').split(',');
        var list = [];
        names.forEach(function(item, index){
            var aObj = {};
            aObj[that.nameField] = item;
            aObj[that.valueField] = values[index];
            list.push(aObj);
        })
        this.setValue(list);
    }

    /**
     * 根据配置项进行html的设置
     */
    SelectTree.prototype.renderHtml = function(){
        var id = this.id;
        this.box.addClass('yby-select-tree ' + this.mode).html(
            (!this.label ? '' : ('<div class="yby-select-tree-item label">'+ this.label +'</div>'))
            + '<div class="yby-select-tree-item content">'
                + '<div class="content-item input-box"><input class="tree-input input" /></div>'
                + '<div class="content-item tree-box hide">'
                    + '<div class="tree-box-inner">'
                        + '<span class="top-arrow"></span>'
                        + (!this.searchConfig.enable ? '' : '<div class="search-box"><input class="search input" type="text" placeholder="请输入进行搜索" /></div>')
                        + '<div id="'+ id +'_ztree" class="ztree"></div>'
                        + '<div class="tree-box-handle"></div>'
                    + '</div>'
                + '</div>'
            + '</div>'
        );
        this.box.find('.tree-box-handle').html(
            '<div class="handle-box">'
            + '<div class="check-all"><input type="checkbox" id="'+ id +'_check_all" /><label for="'+ id +'_check_all">全选</label></div>'
            + '<div class="btn-box">'
                + '<span class="btn btn-smaller ok" data-type="ok">确定</span>'
                + '<span class="btn btn-smaller clear" data-type="clear">清空</span>'
            + '</div>'
            + '</div>'
        );
    }

    SelectTree.prototype.getDataByLevel = function(data, level){
        var deepload = function(list, l){
            return list.map(function(item){
                if(item.children && item.children.length > 0 && l < level){
                    item.children = deepload(item.children, l + 1);
                }else{
                    item.children = null;
                }
                item.nocheck = l == level ? false : true;
                return item;
            })
        }
        return deepload(data, 1);
    }

    /**
     * 根据配置项初始化树形结构
     */
    SelectTree.prototype.showTree = function(){
        var id = this.id, treeConfig = this.treeConfig, treeData = this.treeData;
        if(this.showLevel > 0){
            treeData = this.getDataByLevel(treeData, this.showLevel);
        }
        this.treeObj = $.fn.zTree.init($('#'+id+'_ztree'), treeConfig, treeData);
    }

    /**
     * 过滤需要显示的节点
     */
    SelectTree.prototype.filterFunc = function(node, level, text){
        var reg = new RegExp(text);
        // 如果不设置level，则按照全局进行搜索
        if(typeof level != 'number' || level <= 0){
            var res = this.treeObj.getNodesByParamFuzzy('name', text, node);
            var flag = res.length > 0 ? true : false;// 子节点是否有匹配的；
            return reg.test(node.name) || flag
        }
        // 当节点level小于当前查询的level的时候，全部显示
        if(node.level + 1 > level){
            return true;
        }
        // 当节点level=当前查询的level的时候
        if(node.level + 1 == level){
            return reg.test(node.name)
        }
        // 当节点level小于当前查询的level的时候，查询当前节点的子集是否可以模糊搜索到name，level控制在node.level到level之间
        var preNodes = this.treeObj.getNodesByFilter(function(aNode){
            return aNode.level + 1 <= level ? reg.test(aNode.name) : false;
        }, false, node);
        return preNodes.length > 0 ? true : false;
    }

    /**
     * 搜索树形节点
     * @param {string} text - 模糊搜索的方法
     * @param {number} level - 搜索的树形层级，没有则进行整个树形的搜索
     */
    SelectTree.prototype.searchByText = function(text){
        var level = this.searchConfig.level;
        var that = this;
        if(this.hideNodes){
            // 如果hide nodes存在则显示这些隐藏的节点
            this.treeObj.showNodes(this.hideNodes);
        }
        // 记录上一次的hide nodes
        this.hideNodes = this.treeObj.getNodesByFilter(function(node){
            if(that.searchConfig.filter){
                // 如果有自定义过滤方法，则按照自定义的过滤方法显示
                return !that.searchConfig.filter(node, text);
            }
            return !that.filterFunc(node, level, text);
        });
        this.treeObj.hideNodes(this.hideNodes);
        this.treeObj.expandAll(true);
    }

    /**
     * 隐藏tree面板
     */
    SelectTree.prototype.hideTreeContent = function(){
        if(!this.box.find('.tree-box').hasClass('hide')){
            this.box.find('.tree-box').addClass('hide');
        }
    }

    /**
     * 设置组件的监听事件
     */
    SelectTree.prototype.setListener = function(){
        // 监听组件的输入框获取焦点事件
        this.box.off('focus', '.tree-input', this.inputFocus.bind(this));
        this.box.on('focus', '.tree-input', this.inputFocus.bind(this));

        // 监听组件的输入框的失去焦点事件
        this.box.off('blur', '.tree-input', this.inputBlur.bind(this));
        this.box.on('blur', '.tree-input', this.inputBlur.bind(this));

        // 监听搜索框的input事件
        this.box.off('input', '.search-box .search', this.inputInput.bind(this));
        this.box.on('input', '.search-box .search', this.inputInput.bind(this));

        // 监听选择面板的操全选操作
        this.box.off('click', '.handle-box .check-all input[type=checkbox]', this.checkAllClick.bind(this));
        this.box.on('click', '.handle-box .check-all input[type=checkbox]', this.checkAllClick.bind(this));

        // 监听选择面板的操作按钮的点击事件
        this.box.off('click', '.btn-box .btn', this.btnClick.bind(this));
        this.box.on('click', '.btn-box .btn', this.btnClick.bind(this));

        // 监听content区域的点击事件，阻止事件传播
        this.box.off('click', '.content', this.boxClick.bind(this));
        this.box.on('click', '.content', this.boxClick.bind(this));

        // 监听content外部区域的点击事件
        $(document).off('click', this.outClick.bind(this));
        $(document).on('click', this.outClick.bind(this));
    }

    /**
     * 组件用到的监听事件函数
     * 单独写出来方便调用，也防止多次监听
     * 输入框获取焦点事件
     */
    SelectTree.prototype.inputFocus = function(e){
        var _this = e.target;
        // 隐藏其他的selectTree的选择框
        $('.yby-select-tree .tree-box').map(function(index, item){
            if(!$(item).hasClass('hide')){
                $(item).addClass('hide');
            }
        })
        // 显示当前的选择框
        this.box.find('.tree-box').removeClass('hide');
        $(_this).blur();
        this.resetTreeByInputValue()
    }
    /**
     * 输入框失去焦点事件
     */
    SelectTree.prototype.inputBlur = function(e){
        var _this = e.target;
        console.log('blur');
    }
    /**
     * 输入框的input事件
     */
    SelectTree.prototype.inputInput = function(e){
        var _this = e.target;
        var that = this;
        var value = $(_this).val();
        // 用户输入的时候，进行防抖设置
        if(this.timer){
            clearTimeout(this.timer);
        }
        this.timer = setTimeout(function(){
            console.log(value);
            that.searchByText(value);
            if(that.onInput){
                that.onInput(value);
            }
        }, 300);
    }

    SelectTree.prototype.checkAllClick = function(e){
        e.stopPropagation();
        var _this = e.target;
        var checked = _this.checked;
        console.log('checked', checked);
        this.treeObj.checkAllNodes(checked);
    }

    /**
     * 选择面板的操作按钮的点击事件监听
     */
    SelectTree.prototype.btnClick = function(e){
        var _this = e.target;
        var type = $(_this).data('type');
        var nodes = this.treeObj.getCheckedNodes(true);
        console.log(nodes, type);
        if(type == 'ok'){
            var values = this.getValue();
            this.setInputValue(nodes);
            console.log(values);
        }else if(type == 'clear'){
            this.treeObj.checkAllNodes(false);
            this.setInputValue([]);
        }
        this.hideTreeContent();
    }

    /**
     * 组件中的content的点击事件
     */
    SelectTree.prototype.boxClick = function(e){
        e.preventDefault();
        e.stopPropagation();
    }
    /**
     * content外的区域点击事件
     */
    SelectTree.prototype.outClick = function(e){
        this.hideTreeContent();
    }

    return SelectTree;

});